import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * Created with IntelliJ IDEA.
 * Description: 网络编程最简单的客户端服务器程序——回显服务
 * 即请求内容是啥，得到的回应就是啥
 * UDP回显服务器
 */
public class UdpEchoServer {
    //创建DatagramSocket对象
    private DatagramSocket socket = null;

    // 构造方法，传递端口号，必须手动指定端口号，因为客户端想要访问服务器的话
    // 必须事先知道服务器的IP和端口号
    //可能创建失败
    //1. 传递的端口号被占用
    //2. 该进程已经开了足够多的文件，无法再开辟新的文件
    public UdpEchoServer(int port) throws SocketException {
        this.socket = new DatagramSocket(port);
    }

    //启动服务器
    public void start() throws IOException {
        System.out.println("启动服务器！");
        //UDP 不需要建立连接，直接接收从客服端发来的数据即可
        while(true) {
            //1. 读取客户端发来的请求

            //要读取请求，就需要先创建一个DatagramPacket数据报
            //创建数据报时需要指定大小
            DatagramPacket requestPacket = new DatagramPacket(new byte[1024], 1024);
            //此处同样可能会有异常，是我们熟知的IOException，另外此处如果收不到请求，会发生阻塞
            socket.receive(requestPacket);
            //将请求转为字符串类型
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength(), "UTF-8");
            //2. 根据请求计算响应
            String response = process(request);
            //3. 把响应发回客户端
            //把相应发回客户端同样需要一个数据报作为媒介
            //把字符串的响应按照字节数组写回数据报，需要指定字节长度
            //我们在发回客户端时，需要说明发给哪个客户端，因此我们需要从请求中获取到客户端的IP + 端口
            //因此创建数据报传参时应该传递IP + 端口
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length
                , requestPacket.getSocketAddress());
            socket.send(responsePacket);
            //我们可以看一下发来请求的客户端的IP + 端口，请求内容和响应
            System.out.printf("[%s : %d] req: %s, resp: %s\n",
                    requestPacket.getAddress().toString(),requestPacket.getPort(), request, response);
        }
    }

    //由于我们是回显服务，因此直接返回请求即可
    protected String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer udpEchoServer = new UdpEchoServer(9080);
        udpEchoServer.start();
    }
}
